package com.hymjweb.demo.hymj.login_manage.controller;

import com.alibaba.fastjson.JSONObject;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.hymjweb.demo.framework.cache.service.GlobalCacheService;
import com.hymjweb.demo.framework.sys.BaseController;
import com.hymjweb.demo.framework.sys.SysConstant;
import com.hymjweb.demo.framework.util.DataTypeUtil;
import com.hymjweb.demo.framework.util.DateUtil;
import com.hymjweb.demo.hymj.basic_data_manage.xt_compay_login.bean.XtCompanyLoginPojo;
import com.hymjweb.demo.hymj.department_manage.bean.XtDepartmentPojo;
import com.hymjweb.demo.hymj.department_manage.service.XtDepartmentService;
import com.hymjweb.demo.hymj.login_manage.service.LoginService;
import com.hymjweb.demo.hymj.system_maintenance.user.bean.XtUserPojo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;

/**
 * @BelongsProject: demo1
 * @BelongsPackage: com.hymjweb.demo.hymj.system_login.controller
 * @Author: luoge
 * @CreateTime: 2019-10-15 17:51
 * @Description: 登录和注销控制器
 */
@Slf4j
@Controller
@RequestMapping("/login")
public class LoginController extends BaseController {

    @Autowired
    private Producer captchaProducer;

    @Autowired
    private LoginService loginService;

    @Autowired
    private XtDepartmentService xtDepartmentService;

    @Autowired
    private GlobalCacheService globalCacheService;

    @Value(("${company.login.id}"))
    private String companyLoginId;

    private String forwardLoginUrl = "forward:/login/login";
    private String redirectMainPageUrl = "redirect:/main/page";

    @RequestMapping("/login")
    public String login() {

        // 获取系统公司登录对象
        XtCompanyLoginPojo xtCompanyLoginPojo = (XtCompanyLoginPojo)globalCacheService.getCacheObjectByCacheNameAndId(SysConstant.CACHE_XT_COMPANY_LOGIN,companyLoginId);

        // 这是到期日期
        Long validity = xtCompanyLoginPojo.getValidity();

        // 这是当前日期
        Long currentValidity = System.currentTimeMillis();


        // 有两种情况，
        // 1.当前日期大于到期日期

        if(validity<currentValidity){
            return "pages/invalid";
        }

        // 2.距离结束日期小于30天
        int validDays = DateUtil.diffDate(validity,currentValidity);
        if(validDays<30){
            setRequestAttribute("validDays",validDays);
        }
        else{
            setRequestAttribute("validDays",0);
        }

        setRequestAttribute("company", JSONObject.toJSON(xtCompanyLoginPojo));

        // 初始登录时没有走拦截器，所以要先设置其基本路径
        setRequestBaseParam();

        return "pages/login";
    }

    @GetMapping("/logout")
    public String logout() {
        try {
            // 获取登录主体Subject
            Subject currentUser = SecurityUtils.getSubject();
            currentUser.logout();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return "redirect:/login/login";
    }

    @RequestMapping("/loginCheck")
    public String loginCheck(@RequestParam(value = "mobile") String mobile, @RequestParam(value = "passWord") String passWord, @RequestParam(value = "checkCode") String checkCode, HttpSession session, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 初始登录时没有走拦截器，所以要先设置其基本路径
        setRequestBaseParam();

        if (checkCode == null || DataTypeUtil.isEmptyStr(checkCode)) {
            request.setAttribute("errorMsg", "验证码没有输入!");
            return "forward:/login/login";
        }

        // 获取Session中的验证码
        String sessionCheckCode = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);

        if (sessionCheckCode == null || !checkCode.equals(sessionCheckCode)) {
            request.setAttribute("errorMsg", "验证码错误!");
            return "forward:/login/login";
        }

        if (mobile == null || DataTypeUtil.isEmptyStr(mobile) || passWord == null || DataTypeUtil.isEmptyStr(passWord)) {
            request.setAttribute("errorMsg", "登录账号或密码没有输入!");
            return "forward:/login/login";
        }

        // 根据 mobile 与 passWord 检索登录对象
        XtUserPojo pojo = loginService.getSystemUserPojoByMobileAndPassWord(mobile, passWord);

        if (pojo == null) {
            request.setAttribute("errorMsg", "根据登录账号与密码检索用户失败!");
            return "forward:/login/login";
        }

        // 根据用户 ID 检索用户部门对象
        XtDepartmentPojo departmentPojo = xtDepartmentService.getDepartmentPojoByUserId(pojo.getId());

        if (departmentPojo == null) {
            request.setAttribute("errorMsg", "登录用户部门没有设置，请联系管理员!");
            return "forward:/login/login";
        }

        // 会话配置
        session.setAttribute(SysConstant.SESSION_LOGIN_USER_KEY, pojo);
        session.setAttribute(SysConstant.SESSION_LOGIN_USER_DEPARTMENT_KEY, departmentPojo);

        // 转向main
        return "redirect:/main/page";
    }

    @RequestMapping("/shiroLoginCheck")
    public String shiroLoginCheck(@RequestParam(value = "mobile") String mobile, @RequestParam(value = "passWord") String passWord, @RequestParam(value = "checkCode") String checkCode, HttpServletRequest request) throws Exception {
        // 初始登录时没有走拦截器，所以要先设置其基本路径
        this.setRequestBaseParam();

        // 获取登录主体Subject
        Subject currentUser = SecurityUtils.getSubject();

        // 获取登录主体的Session
        Session session = currentUser.getSession();

        if (checkCode == null || DataTypeUtil.isEmptyStr(checkCode)) {
            this.setRequestAttribute("errorMsg", "没有输入验证码!");
            return forwardLoginUrl;
        }

        // 获取Session中的验证码
        String sessionCheckCode = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);

        if (sessionCheckCode == null || !checkCode.equals(sessionCheckCode)) {
            this.setRequestAttribute("errorMsg", "验证码错误!");
            return forwardLoginUrl;
        }

        if (mobile == null || DataTypeUtil.isEmptyStr(mobile) || passWord == null || DataTypeUtil.isEmptyStr(passWord)) {
            this.setRequestAttribute("errorMsg", "登录账号或密码没有输入!");
            return forwardLoginUrl;
        }


        // 验证用户是否验证，即是否登录
        if (currentUser.isAuthenticated()) {
            // 已经登录过，直接转向main
            return redirectMainPageUrl;
        }

        // 还没有登录过，则进行下面的验证步骤

        String msg = "";
        // 把用户名和密码封装为 UsernamePasswordToken 对象
        UsernamePasswordToken token = new UsernamePasswordToken(mobile, passWord);

        // remembermMe记住密码
        token.setRememberMe(true);

        try {
            // 执行登录. 此时会调用MyShiroRealm中的用户认证方法(这是重点)
            currentUser.login(token);

            // 根据 mobile 与 passWord 检索登录对象
            XtUserPojo pojo = (XtUserPojo) currentUser.getPrincipal();

            if (pojo == null) {
                request.setAttribute("errorMsg", "根据登录账号与密码检索用户失败!");
                return forwardLoginUrl;
            }

            // 根据用户 ID 检索用户部门对象
            XtDepartmentPojo departmentPojo = xtDepartmentService.getDepartmentPojoByUserId(pojo.getId());

            if (departmentPojo == null) {
                request.setAttribute("errorMsg", "登录用户部门没有设置，请联系管理员!");
                return forwardLoginUrl;
            }

            session.setAttribute(SysConstant.SESSION_LOGIN_USER_KEY, pojo);
            session.setAttribute(SysConstant.SESSION_LOGIN_USER_DEPARTMENT_KEY, departmentPojo);

            // 转向main
            return redirectMainPageUrl;

        } catch (IncorrectCredentialsException e) {
            msg = "登录密码错误";
        } catch (ExcessiveAttemptsException e) {
            msg = "登录失败次数过多";
        } catch (LockedAccountException e) {
            msg = "帐号已被锁定";
        } catch (DisabledAccountException e) {
            msg = "帐号已被禁用";
        } catch (ExpiredCredentialsException e) {
            msg = "帐号已过期";
        } catch (UnknownAccountException e) {
            msg = "帐号不存在";
        } catch (UnauthorizedException e) {
            msg = "您没有得到相应的授权！";
        } catch (Exception e) {
            msg = "未知错误！";
        }

        request.setAttribute("errorMsg", msg);

        return forwardLoginUrl;
    }


    /**
     * 生成验证码，存入到session同时以图片形式回送到登录首页
     *
     * @param resp
     * @throws IOException
     */
    @GetMapping("/kaptcha")
    public void kaptcha(HttpServletResponse resp) throws IOException {
        // Set to expire far in the past.
        resp.setDateHeader("Expires", 0);
        // Set standard HTTP/1.1 no-cache headers.
        resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
        resp.addHeader("Cache-Control", "post-check=0, pre-check=0");
        // Set standard HTTP/1.0 no-cache header.
        resp.setHeader("Pragma", "no-cache");

        // return a jpeg
        resp.setContentType("image/jpeg");

        // create the text for the image
        String capText = this.captchaProducer.createText();

        // 获取登录主体
        Subject currentUser = SecurityUtils.getSubject();

        // 获取主体Session
        Session currentUserSession = currentUser.getSession();

        // store the text in the session
        currentUserSession.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);

        // store the date in the session so that it can be compared
        // against to make sure someone hasn't taken too long to enter
        // their kaptcha
        currentUserSession.setAttribute(Constants.KAPTCHA_SESSION_DATE, new Date().getTime());

        // create the image with the text
        BufferedImage bi = this.captchaProducer.createImage(capText);

        ServletOutputStream out = resp.getOutputStream();

        // write the data out
        ImageIO.write(bi, "jpg", out);
        out.close();
    }


}
